/*
 * Copyright (C) 2011-2015 ShenZhen iBOXPAY Information Technology Co.,Ltd.
 * 
 * All right reserved.
 * 
 * This software is the confidential and proprietary
 * information of iBoxPay Company of China. 
 * ("Confidential Information"). You shall not disclose
 * such Confidential Information and shall use it only
 * in accordance with the terms of the contract agreement 
 * you entered into with iBoxpay inc.
 *
 */

package com.iboxpay.sdk;

import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

//import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

/**
 * The class RSACoder.
 *
 * Description: 
 *
 * @author: nieminjie
 * @since: 2016年2月29日	
 * @version: $Revision$ $Date$ $LastChangedBy$
 *
 */

public class RSACoder {

//	public static Base64 base64 = new Base64();

	// 算法
	public static final String KEY_ALGORITHM = "RSA";
	// 算法/工作模式/填充方式
	public final static String CHIPER_ALGORITHM = "RSA/ECB/PKCS1Padding";
	// 签名算法
	public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
	// 密钥长度
	public static final int KEY_SIZE = 1024;

	public static final String PUBLIC_KEY = "RSAPublicKey";
	public static final String PRIVATE_KEY = "RSAPrivateKey";

	/**
	 * 用私钥对信息生成数字签名
	 * 
	 * @param data 加密数据
	 * @param privateKey 私钥
	 * @return
	 */
	public static byte[] sign(byte[] data, String privateKey) {
		return sign(data, getKeyDecodedBytes(privateKey));
	}

	/**
	 * 用私钥对信息生成数字签名
	 * 
	 * @param data 加密数据
	 * @param privateKey 私钥
	 * @return
	 */
	public static byte[] sign(byte[] data, byte[] privateKey) {
		try {
			// 构造PKCS8EncodedKeySpec对象
			PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
			// KEY_ALGORITHM 指定的加密算法
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			// 取私钥匙对象
			PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
			// 用私钥对信息生成数字签名
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initSign(priKey);
			signature.update(data);
			return signature.sign();
		} catch (Exception e) {
			throw new RuntimeException("Error when verify sign, ermsg: " + e.getMessage(), e);
		}
	}

	/**
	 * 校验数字签名
	 * 
	 * @param data 数据
	 * @param publicKey 公钥
	 * @param sign 数字签名
	 * @return
	 */
	public static boolean verifyByPublicKey(byte[] data, String publicKey, byte[] sign) {
		return verifyByPublicKey(data, getKeyDecodedBytes(publicKey), sign);
	}

	/**
	 * 校验数字签名
	 * 
	 * @param data 数据
	 * @param publicKey 公钥
	 * @param sign 数字签名
	 * @return
	 */
	public static boolean verifyByPublicKey(byte[] data, byte[] publicKey, byte[] sign) {
		try {
			// 构造X509EncodedKeySpec对象
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
			// KEY_ALGORITHM 指定的加密算法
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			// 取公钥匙对象
			PublicKey pubKey = keyFactory.generatePublic(keySpec);
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initVerify(pubKey);
			signature.update(data);
			// 验证签名是否正常
			return signature.verify(sign);
		} catch (Exception e) {
			throw new RuntimeException("Error when verify sign, ermsg: " + e.getMessage(), e);
		}
	}

	/**
	 * 私钥解密
	 * 
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] decryptByPrivateKey(byte[] data, String key) {
		return decryptByPrivateKey(data, getKeyDecodedBytes(key));
	}

	/**
	 * 私钥解密
	 * 
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] decryptByPrivateKey(byte[] data, byte[] key) {
		try {
			// 取得私钥
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
			// 生成私钥
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
			// 对数据解密
			Cipher cipher = Cipher.getInstance(CHIPER_ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, privateKey);

			return cipher.doFinal(data);
		} catch (Exception e) {
			throw new RuntimeException("Error when decrypt key, ermsg: " + e.getMessage(), e);
		}
	}

	/**
	 * 公钥解密
	 * 
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] decryptByPublicKey(byte[] data, String key) {
		return decryptByPublicKey(data, getKeyDecodedBytes(key));
	}

	/**
	 * 公钥解密
	 * 
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] decryptByPublicKey(byte[] data, byte[] key) {
		try {
			// 取得公钥
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
			// 生成公钥
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PublicKey publicKey = keyFactory.generatePublic(keySpec);
			// 对数据解密
			Cipher cipher = Cipher.getInstance(CHIPER_ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, publicKey);

			return cipher.doFinal(data);
		} catch (Exception e) {
			throw new RuntimeException("Error when decrypt key, ermsg: " + e.getMessage(), e);
		}
	}

	/**
	 * 私钥加密
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] encryptByPrivateKey(byte[] data, String key) {
		return encryptByPrivateKey(data, getKeyDecodedBytes(key));
	}

	/**
	 * 私钥加密
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] encryptByPrivateKey(byte[] data, byte[] key) {
		try {
			// 取得私钥
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
			// 生成私钥
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
			// 对数据加密
			Cipher cipher = Cipher.getInstance(CHIPER_ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);

			return cipher.doFinal(data);
		} catch (Exception e) {
			throw new RuntimeException("Error when encrypt key, ermsg: " + e.getMessage(), e);
		}
	}

	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] encryptByPublicKey(byte[] data, String key) {
		return encryptByPublicKey(data, getKeyDecodedBytes(key));
	}

	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param key
	 * @return
	 */
	public static byte[] encryptByPublicKey(byte[] data, byte[] key) {
		try {
			// 取得公钥
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
			// 生成公钥
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PublicKey publicKey = keyFactory.generatePublic(keySpec);
			// 对数据加密
			Cipher cipher = Cipher.getInstance(CHIPER_ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);

			return cipher.doFinal(data);
		} catch (Exception e) {
			throw new RuntimeException("Error when encrypt key, ermsg: " + e.getMessage(), e);
		}
	}

	/**
	 * 初始化密钥
	 * @return
	 */
	public static Map<String, Object> initKey() {
		try {
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
			keyPairGen.initialize(KEY_SIZE);

			KeyPair keyPair = keyPairGen.generateKeyPair();

			RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
			RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

			Map<String, Object> keyMap = new HashMap<String, Object>(2);
			keyMap.put(PUBLIC_KEY, publicKey);
			keyMap.put(PRIVATE_KEY, privateKey);
			return keyMap;
		} catch (Exception e) {
			throw new RuntimeException("Error when init key, ermsg: " + e.getMessage(), e);
		}
	}

	/**
	 * 获取私钥
	 * @param keyMap
	 * @return
	 * @throws Exception
	 */
	public static byte[] getPrivateKey(Map<String, Object> keyMap) {
		Key key = null;
		try {
			key = (Key) keyMap.get(PRIVATE_KEY);
		} catch (Exception e) {
			throw new RuntimeException("Error when getPrivateKey, ermsg: " + e.getMessage(), e);
		}
		return key.getEncoded();
	}

	/**
	 * 获取公钥
	 * @param keyMap
	 * @return
	 * @throws Exception
	 */
	public static byte[] getPublicKey(Map<String, Object> keyMap) {
		Key key = null;
		try {
			key = (Key) keyMap.get(PUBLIC_KEY);
		} catch (Exception e) {
			throw new RuntimeException("Error when getPrivateKey, ermsg: " + e.getMessage(), e);
		}
		return key.getEncoded();
	}

	/**
	 * 获取公钥私钥
	 * @param keyMap
	 * @return
	 */
	public static Map<String, Object> getKeys() {
		Map<String, Object> keyMap = RSACoder.initKey();
		byte[] pubKey = RSACoder.getPublicKey(keyMap);
		byte[] priKey = RSACoder.getPrivateKey(keyMap);
		String publickey = new String("");//base64.encode(pubKey));
		String privatekey = new String("");//base64.encode(priKey));
		Map<String, Object> keys = new HashMap<String, Object>();;
		keys.put(RSACoder.PUBLIC_KEY, publickey);
		keys.put(RSACoder.PRIVATE_KEY, privatekey);
		return keys;
	}

	public static byte[] intToBCD(int len) {
		byte[] bcdByte = new byte[2];
		bcdByte[0] = (byte) ((len / 100) / 10 * 0x10 + (len / 100) % 10);
		bcdByte[1] = (byte) ((len % 100) / 10 * 0x10 + (len % 100) % 10);
		return bcdByte;
	}

	/**
	 * 获取解码后的原始key
	 * @param key
	 * @return
	 */
	private static byte[] getKeyDecodedBytes(String key) {
		if (StringUtils.isNotBlank(key)) {
			return key.getBytes();//base64.decode(key.getBytes());
		}
		return null;
	}

	/**
	 * test
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws Exception {
		Map<String, Object> keysMap = getKeys();
		System.out.println("RSA公钥:" + keysMap.get(RSACoder.PUBLIC_KEY) + "\n" + "RSA私钥:" + keysMap.get(RSACoder.PRIVATE_KEY));
	}
}
